package com.libreaccess.reporting.scheduler;

import java.io.File;
import java.net.URLEncoder;
import java.sql.Connection;
import java.util.HashMap;

import javax.annotation.Resource;

import net.sf.jasperreports.engine.JRParameter;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.export.JRCsvExporter;
import net.sf.jasperreports.engine.export.JRCsvExporterParameter;
import net.sf.jasperreports.engine.export.JRPdfExporter;
import net.sf.jasperreports.engine.export.JRPdfExporterParameter;
import net.sf.jasperreports.engine.export.JRXlsExporter;
import net.sf.jasperreports.engine.export.JRXlsExporterParameter;
import net.sf.jasperreports.engine.type.WhenNoDataTypeEnum;

import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import com.libreaccess.reporting.beans.ReportsDAO;
import com.libreaccess.reporting.beans.ReportsDAOImpl;
import com.libreaccess.reporting.utils.CustomFileResolver;
import com.libreaccess.reporting.utils.Logger;
import com.libreaccess.reporting.utils.Mail;
import com.libreaccess.reporting.utils.ReportUtil;
import com.libreaccess.reporting.utils.ReportingPortletDataPerUser;
import com.libreaccess.reporting.utils.SimpleUtils;
import com.libreaccess.reporting.utils.UserLiferay;
import com.libreaccess.reporting.utils.JasperUtils;
import com.libredigital.reporting.schema.MyReport;
import com.libredigital.reporting.schema.ReportView;

public class SchedulerJob implements Job {

	public static final String REPORT_FOLDER = "//reports//";

	@Resource
	private static ReportsDAO rDao;

	public void setrDao(ReportsDAO rDao) {
		SchedulerJob.rDao = rDao;
	}

	final Logger logger = new Logger(getClass());

	/* this method calls when trigger is fired
	 * @see org.quartz.Job#execute(org.quartz.JobExecutionContext)
	 * @param JobExecutionContext context
	 * @return void
	 */
	public void execute(JobExecutionContext context) throws JobExecutionException {
		JobDataMap dataMap = context.getJobDetail().getJobDataMap();
		try {
			populateReport((ReportUtil) dataMap.get("parameters"));
		} catch (Exception ex) {
			logger.error(ex.getMessage());
		}
	}

	/* this method generates the report from trigger's data
	 * @param ReportUtil data
	 * @return void
	 */
	private void populateReport(ReportUtil data) throws Exception {
		boolean isException = false;
		logger.debug("I'm inside schedule");
		logger.debug("user:"+data.getUserName());
		
		if (rDao == null)
		{
			rDao = new ReportsDAOImpl();
		}
		String sFolder = data.getReportsFolder().substring(0,data.getReportsFolder().lastIndexOf(File.separatorChar)+1);
		logger.debug("sFolder="+sFolder);
		
		logger.debug("Recip.size:"+data.getRecipients().size());
		for (UserLiferay us: data.getRecipients()) {
			
			File repFolder = new File(String.format("%s%s_%s", sFolder, us.getUserId(),us.getEmail().replace('@', '_')));
			repFolder.mkdirs();

			logger.debug("!!!!!!!!!data.getReportFormat():"+data.getReportFormat());
			logger.debug("!!!!!!!!data.getViewId():" + data.getViewId());
			ReportView view = rDao.getReportViewById(data.getViewId());
			MyReport myRep = rDao.getMyReportById(data.getMyReportId());

			String rptName = String.format("%s_%s.%s", myRep.getName(), SimpleUtils.formatCurrentDateAndTime(), myRep.getReportName());
			logger.debug("Report is named :"+rptName);
		
			ReportingPortletDataPerUser reportData = new ReportingPortletDataPerUser();
			reportData.getReportUtil().setParameters(data.getParameters());
		
			reportData.setDesign(JasperUtils.loadReport(view.getJrxml().getBytes("UTF-8")));
		
			logger.debug("Data prepared");
		
			reportData = JasperUtils.setupParameters(reportData); //we have parameters and model
			logger.debug("All parameters are set");		
		
			Connection con;
			if (view.getDatasourceId() != 0l)
			{
				con = JasperUtils.getReportViewConnection(rDao.getReportDSById(view.getDatasourceId()));
				logger.debug("Report View:"+view.getId()+" uses the connection with id:"+view.getDatasourceId()); 
			}
			else
			{
				con = JasperUtils.getDataSource().getConnection();
				logger.debug("Report View:"+view.getId()+" uses default connection");
			}
		
			HashMap<String, Object> mdl = reportData.getModel();
			mdl.put(JRParameter.REPORT_FILE_RESOLVER, new CustomFileResolver(rDao.setLogMaster(view.getId(), data.getUserName(), reportData.getParameters())));
			String completedReportLink=null;
			try {
				JasperReport jasperReport = JasperCompileManager.compileReport(reportData.getDesign());
				if (jasperReport.getWhenNoDataTypeValue() == WhenNoDataTypeEnum.NO_PAGES) {
					jasperReport.setWhenNoDataType(WhenNoDataTypeEnum.ALL_SECTIONS_NO_DETAIL);
				}
				JasperPrint print = JasperFillManager.fillReport(jasperReport, mdl, con);
				logger.debug("dest:"+repFolder.getPath()+File.separator+ rptName+ "." + data.getReportFormat());
				switch(data.getReportFormat()) {
				case PDF:
					JRPdfExporter exporterPDF = new JRPdfExporter();
					exporterPDF.setParameter(JRPdfExporterParameter.JASPER_PRINT, print);
					exporterPDF.setParameter(JRPdfExporterParameter.OUTPUT_FILE_NAME, repFolder.getPath()+File.separator+ rptName+ "." + data.getReportFormat());
					exporterPDF.exportReport();
					break;
				case CSV:
					JRCsvExporter exporterCSV = new JRCsvExporter();
					exporterCSV.setParameter(JRCsvExporterParameter.JASPER_PRINT, print);
					exporterCSV.setParameter(JRCsvExporterParameter.OUTPUT_FILE_NAME, repFolder.getPath()+File.separator+ rptName+ "." + data.getReportFormat());
					exporterCSV.exportReport();
					break;
				case XLS:
					JRXlsExporter exporterXLS = new JRXlsExporter();
					exporterXLS.setParameter(JRXlsExporterParameter.JASPER_PRINT, print);
					exporterXLS.setParameter(JRXlsExporterParameter.OUTPUT_FILE_NAME, repFolder.getPath()+File.separator+ rptName+ "." + data.getReportFormat());
					exporterXLS.exportReport();
					break;
				case HTML:
					JasperExportManager.exportReportToHtmlFile(print, repFolder.getPath()+File.separator+ rptName+ "." + data.getReportFormat());
					break;
				}

				completedReportLink = data.getUrl()+URLEncoder.encode(rptName, "UTF-8")+ "." + data.getReportFormat();
				logger.debug("Link is:"+completedReportLink);

			}
			catch (Exception ex) {
				isException = true;
			}
			finally {
				logger.debug("isException:"+isException);
				if (con != null) {
					con.close();
				}
			}
		
			Mail.sendMessage(us, myRep.getName(), completedReportLink, isException);
		}
//		data.setSchedulerCountToRun(data.getSchedulerCountToRun() - 1);
//		logger.debug("Trigger "+data.getTriggerId()+" countToRun=" +data.getSchedulerCountToRun());
		SchedulerManager.addJob(data, false); //update data (decrease recurring count)
		
/*		setrDao(new ReportsDAOImpl()); // temporary

		JasperPrint jasperPrint = null;
		JasperReport jasperReport = null;
		Report report = rDao.getById(data.getReportId());

		jasperReport = JasperCompileManager.compileReport(Utils.loadReport(report.getJrxml().getBytes("UTF-8")));
		if (jasperReport.getWhenNoDataTypeValue() == WhenNoDataTypeEnum.NO_PAGES)
		{
			jasperReport.setWhenNoDataType(WhenNoDataTypeEnum.ALL_SECTIONS_NO_DETAIL);
		}
		jasperPrint = JasperFillManager.fillReport(jasperReport, data.getParameters(), Utils.getDataSource().getConnection());
		String reportName = report.getName() + (new SimpleDateFormat("MM-dd-yyyy-hh-mm").format(new Date()));

		ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
		OutputStream output;
		switch (data.getReportFormat()) {
		case pdf:
			JRPdfExporter exporterPDF = new JRPdfExporter();
			exporterPDF.setParameter(JRPdfExporterParameter.JASPER_PRINT, jasperPrint);
			exporterPDF.setParameter(JRPdfExporterParameter.OUTPUT_STREAM, byteArrayOutputStream);
			exporterPDF.exportReport();

			File pdfFile = File.createTempFile(reportName, "." + data.getReportFormat());
			pdfFile.deleteOnExit();
			output = new FileOutputStream(pdfFile);
			output.write(byteArrayOutputStream.toByteArray());
			output.flush();
			output.close();

			exportReport(data, reportName, pdfFile);
			break;
		case html:
			File htmlFile = File.createTempFile(reportName, ".html");
			htmlFile.deleteOnExit();

			JRHtmlExporter exporterHTML = new JRHtmlExporter();
			exporterHTML.setParameter(JRHtmlExporterParameter.JASPER_PRINT, jasperPrint);
			exporterHTML.setParameter(JRHtmlExporterParameter.OUTPUT_FILE_NAME, htmlFile.getCanonicalPath());
			exporterHTML.setParameter(JRHtmlExporterParameter.IS_USING_IMAGES_TO_ALIGN, Boolean.FALSE);
			exporterHTML.exportReport();

//			 zip file and folder 
			File inFolder = new File(htmlFile.getCanonicalPath().substring(0, htmlFile.getCanonicalPath().lastIndexOf(".")) + ".html_files");
			File outFolder = File.createTempFile(reportName, ".zip");
			outFolder.deleteOnExit();
			ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(outFolder)));
			BufferedInputStream in = null;
			byte[] content = new byte[1000];
			if (inFolder.exists()) {
				String files[] = inFolder.list();
				for (int i = 0; i < files.length; i++) {
					in = new BufferedInputStream(new FileInputStream(inFolder.getPath() + "/" + files[i]), 1000);
					out.putNextEntry(new ZipEntry(htmlFile.getName().substring(0, htmlFile.getName().lastIndexOf(".")) + ".html_files/"
							+ files[i]));
					int count;
					while ((count = in.read(content, 0, 1000)) != -1) {
						out.write(content, 0, count);
					}
					out.closeEntry();
				}
			}
			in = new BufferedInputStream(new FileInputStream(htmlFile.getCanonicalPath()), 1000);
			out.putNextEntry(new ZipEntry(htmlFile.getName()));
			int count;
			while ((count = in.read(content, 0, 1000)) != -1) {
				out.write(content, 0, count);
			}
			out.closeEntry();
			out.flush();
			out.close();

			htmlFile.delete();

			exportReport(data, reportName, outFolder);
			break;
		}
		logger.debug("report: " + reportName + "." + data.getReportFormat() + " was generated");

		byteArrayOutputStream = null;*/
	}

}
